﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DotNetCommon;
using DotNetCommon.Data;
using DotNetCommon.Extensions;
using System.Data.Common;
using System.Reflection;
using System.Linq.Expressions;
using DotNetCommon.Logger;
using System.Text;
using System.Diagnostics;
using DBUtil.SqlSegment;
using System.ComponentModel.DataAnnotations.Schema;

namespace DBUtil
{
    /// <summary>
    /// 通用数据库访问对象
    /// </summary>
    public abstract partial class DBAccess
    {
        private static readonly ILogger<DBAccess> logger = LoggerFactory.CreateLogger<DBAccess>();
        #region 设置Settings
        /// <summary>
        /// 设置
        /// </summary>
        public DBSetting Settings { get; protected set; }
        #endregion

        #region 表名或标识符分析/解析
        /// <summary>
        /// 标识符引用标记<para></para>
        /// 如 sqlserver: [],""<para></para>
        /// 如 mysql: ``,""<para></para>
        /// </summary>
        public virtual List<string> QuoteIdentifierCharacters { get; }

        private char[][] _characters = null;
        protected virtual char[][] getQuoteIndentifierCharacters()
        {
            if (_characters == null)
            {
                _characters = new char[QuoteIdentifierCharacters.Count][];
                for (var i = 0; i < QuoteIdentifierCharacters.Count; i++)
                {
                    _characters[i] = QuoteIdentifierCharacters[i].ToArray();
                }
            }
            return _characters;
        }

        /// <summary>
        /// 从给定的名称列表中解析出纯净的name、schema名、数据库名等
        /// </summary>
        /// <param name="name">对象名称，如：<br />
        /// <list type="number">
        /// <item>table1</item>
        /// <item>[table1]、`table1`</item>
        /// <item>[dbo].[table1]、`testdb`.`table1`</item>
        /// <item>testdb.dbo.[table1]</item>
        /// </list>
        /// </param>
        /// <param name="useThisSchemaName">模式名，如果有值则覆盖tableName中的模式名</param>
        /// <param name="useThisDBName">数据库名，如果有值则覆盖tableName中的数据库名</param>
        /// <param name="defaultSchemaName">模式名，如果解析后没有模式名则使用该值</param>
        /// <param name="defaultDBName">数据库名，如果解析后没有数据库名则使用该值</param>
        /// <returns></returns>
        public virtual ObjectName ParseObjectName(string name, string useThisSchemaName = null, string useThisDBName = null, string defaultSchemaName = null, string defaultDBName = null)
        {
            var (db, schema, table) = AnalysisIdentifier(name);
            if (useThisSchemaName.IsNotNullOrEmptyOrWhiteSpace())
            {
                foreach (var item in _characters)
                {
                    if (useThisSchemaName.StartsWith(item[0] + "") && useThisSchemaName.EndsWith(item[1] + ""))
                    {
                        useThisSchemaName = useThisSchemaName.Substring(1, useThisSchemaName.Length - 2);
                        break;
                    }
                }
                schema = useThisSchemaName;
            }
            if (useThisDBName.IsNotNullOrEmptyOrWhiteSpace())
            {
                foreach (var item in _characters)
                {
                    if (useThisDBName.StartsWith(item[0] + "") && useThisDBName.EndsWith(item[1] + ""))
                    {
                        useThisDBName = useThisDBName.Substring(1, useThisDBName.Length - 2);
                        break;
                    }
                }
                db = useThisDBName;
            }
            if (schema.IsNullOrEmptyOrWhiteSpace()) schema = defaultSchemaName.IsNullOrEmptyOrWhiteSpace() ? "" : defaultSchemaName;
            if (db.IsNullOrEmptyOrWhiteSpace()) db = defaultDBName.IsNullOrEmptyOrWhiteSpace() ? "" : defaultDBName;
            var objectName = new ObjectName()
            {
                DataBaseName = db,
                SchemaName = schema,
                Name = table
            };
            var firstQuote = QuoteIdentifierCharacters.FirstOrDefault()[0];
            var lastQuote = QuoteIdentifierCharacters.FirstOrDefault()[1];
            if (objectName.DataBaseName.IsNotNullOrEmptyOrWhiteSpace()) objectName.DataBaseNameQuoted = $"{firstQuote}{objectName.DataBaseName}{lastQuote}";
            else objectName.DataBaseNameQuoted = string.Empty;
            if (objectName.SchemaName.IsNotNullOrEmptyOrWhiteSpace()) objectName.SchemaNameQuoted = $"{firstQuote}{objectName.SchemaName}{lastQuote}";
            else objectName.SchemaNameQuoted = string.Empty;
            if (objectName.Name.IsNotNullOrEmptyOrWhiteSpace()) objectName.NameQuoted = $"{firstQuote}{objectName.Name}{lastQuote}";
            else objectName.NameQuoted = string.Empty;

            var names = new List<string>();
            names.Add(objectName.Name);
            if (objectName.SchemaName.IsNotNullOrEmptyOrWhiteSpace()) names.Add(objectName.SchemaName);
            names.Reverse();
            objectName.NormalName = names.ToStringSeparated(".");
            objectName.NormalNameQuoted = names.Select(i => $"{firstQuote}{i}{lastQuote}").ToStringSeparated(".");
            names.Reverse();
            if (objectName.DataBaseName.IsNotNullOrEmptyOrWhiteSpace()) names.Add(objectName.DataBaseName);
            names.Reverse();
            objectName.FullName = names.ToStringSeparated(".");
            objectName.FullNameQuoted = names.Select(i => $"{firstQuote}{i}{lastQuote}").ToStringSeparated(".");
            return objectName;
        }

        /// <summary>
        /// 从给定的表名或标识符中解析出纯净的 数据库、schema、标识符 名称<para></para>
        /// 如 sqlserver: [testdb].[dbo].[test] => (test,dbo,testdb)<para></para>
        /// 如 mysql: `testdb`.`test` => (testdb,testdb,test)<para></para>
        /// </summary>
        /// <param name="fullIdentifierName">给定的标识符全名</param>
        /// <returns></returns>
        protected virtual (string dbName, string schemaName, string identityName) AnalysisIdentifier(string fullIdentifierName)
        {
            if (fullIdentifierName.IsNullOrEmptyOrWhiteSpace()) throw new ArgumentNullException(nameof(fullIdentifierName));
            fullIdentifierName = fullIdentifierName.Trim();
            var _characters = getQuoteIndentifierCharacters();
            var arr = fullIdentifierName.ToCharArray();
            var _quoteArr = _characters.Select(i => i[0]).ToList();
            var segArr = new List<string>();
            char protect = '\0';
            var t = "";
            for (var index = 0; index < arr.Length; index++)
            {
                var c = fullIdentifierName[index];
                if (protect == '\0')
                {
                    //尚未进入保护模式([],"",``)
                    if (_quoteArr.IndexOf(c) >= 0)
                    {
                        //进入保护模式
                        var _index = _quoteArr.IndexOf(c);
                        protect = _characters[_index][1];
                        segArr.Add(t);
                        t = "";
                        continue;
                    }
                    if (c == '.')
                    {
                        //进行拆分
                        segArr.Add(t);
                        t = "";
                        continue;
                    }
                    t += c;
                }
                else
                {
                    //已经在保护模式中
                    if (c == protect)
                    {
                        //结束保护模式
                        segArr.Add(t);
                        t = "";
                        protect = '\0';
                        continue;
                    }
                    else
                    {
                        t += c;
                        continue;
                    }

                }
            }
            if (t != "")
            {
                segArr.Add(t);
            }
            segArr = segArr.Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
            if (segArr.Count == 1) return (string.Empty, string.Empty, segArr[0]);
            if (segArr.Count == 2) return (string.Empty, segArr[0], segArr[1]);
            if (segArr.Count == 3) return (segArr[0], segArr[1], segArr[2]);
            throw new Exception($"无法解析标识符:{fullIdentifierName}");
        }
        #endregion

        #region 创建DbCommand
        /// <summary>
        /// 创建DbCommand
        /// </summary>
        /// <returns></returns>
        protected abstract DbCommand CreateCommand();

        private DbCommand createCommand(CommandType? commandType, int? timeout, string strSql, DbParameter[] parameters)
        {
            if (strSql.IsNullOrEmptyOrWhiteSpace()) throw new Exception("要执行的sql不能为空!");
            var cmd = CreateCommand();
            if (Settings.CommandTimeout > 0) cmd.CommandTimeout = Settings.CommandTimeout.Value;
            if (commandType != null) cmd.CommandType = commandType.Value;
            if (timeout > 0) cmd.CommandTimeout = timeout.Value;
            if (parameters.IsNotNullOrEmpty()) foreach (var para in parameters) cmd.Parameters.Add(para);
            cmd.Connection = Connection;
            if (IsTran) cmd.Transaction = Transaction;
            cmd.CommandText = strSql;
            return cmd;
        }
        #endregion

        #region 创建DataAdapter
        /// <summary>
        /// 创建DataAdapter
        /// </summary>
        /// <returns></returns>
        protected abstract DataAdapter CreateAdapter(DbCommand cmd);
        #endregion

        #region 基础属性        
        /// <summary>
        /// 事物对象
        /// </summary>
        protected DbTransaction Transaction { get; set; }
        /// <summary>
        /// 连接字符串
        /// </summary>
        public string DBConn { get; protected set; }
        /// <summary>
        /// 数据库类型
        /// </summary>
        public string DBType { get; protected set; }

        /// <summary>
        /// 数据库版本
        /// </summary>
        public virtual string DBVersion { get; }

        /// <summary>
        /// 当前连接的数据库名称
        /// </summary>
        public virtual string DataBase { get; }

        /// <summary>
        /// 默认的架构/模式
        /// </summary>
        public virtual string DefaultSchema { get; }

        /// <summary>
        /// 操作当前数据库的用户名(如果是在sqlserver下,这个值表示当前数据库内的用户名而不是登录数据库使用的用户名,例如: 这里显示的是dbo而不是sa)
        /// </summary>
        public virtual string UserName { get; }

        /// <summary>
        /// 登录数据库使用的用户名
        /// </summary>
        public virtual string LoginUserName { get; }

        /// <summary>
        /// 连接对象
        /// </summary>
        protected DbConnection Connection { get; set; }
        /// <summary>
        /// 记录是否打开了连接,防止多次打开连接
        /// </summary>
        public bool IsOpen => Connection?.State == ConnectionState.Open;
        /// <summary>
        /// 记录是否关闭了连接,防止多次打开连接
        /// </summary>
        public bool IsClose => Connection?.State == ConnectionState.Closed;
        /// <summary>
        /// 记录是否开启了事务,防止多次开启事务
        /// </summary>
        public bool IsTran => Transaction != null;

        /// <summary>
        /// 当前数据库使用的参数的前缀符号
        /// </summary>
        public string ParaPrefix { get; protected set; }
        #endregion

        #region 连接管理
        private bool canClose => _keepConnectCounter <= 0 && readers.IsNullOrEmpty() && Transaction == null && Connection.State != ConnectionState.Closed;

        /// <summary>
        /// 保持打开数据库连接的次数
        /// </summary>
        private int _keepConnectCounter = 0;
        private Stack<IDataReader> readers = new Stack<IDataReader>();

        private void tryClose()
        {
            if (canClose)
                Connection.Close();
        }
        private async Task tryCloseAsync()
        {
            if (canClose)
                await Connection.CloseAsync();
        }
        private void tryOpen()
        {
            if (Connection.State != ConnectionState.Open)
                Connection.Open();
        }
        private async Task tryOpenAsync()
        {
            if (Connection.State != ConnectionState.Open)
                await Connection.OpenAsync();
        }

        protected void RunInConnection(Action action)
        {
            if (action == null) return;
            try
            {
                _keepConnectCounter++;
                tryOpen();
                action.Invoke();
            }
            finally
            {
                _keepConnectCounter--;
                tryClose();
            }
        }
        protected T RunInConnection<T>(Func<T> action)
        {
            if (action == null) throw new ArgumentException(nameof(action));
            try
            {
                _keepConnectCounter++;
                tryOpen();
                var t = action.Invoke();
                return t;
            }
            finally
            {
                _keepConnectCounter--;
                tryClose();
            }
        }
        protected async Task RunInConnectionAsync(Func<Task> action)
        {
            if (action == null) return;
            try
            {
                _keepConnectCounter++;
                await tryOpenAsync();
                await action();
            }
            finally
            {
                _keepConnectCounter--;
                await tryCloseAsync();
            }
        }
        protected async Task<T> RunInConnectionAsync<T>(Func<Task<T>> action)
        {
            if (action == null) throw new ArgumentException(nameof(action));
            try
            {
                _keepConnectCounter++;
                await tryOpenAsync();
                var t = await action.Invoke();
                return t;
            }
            finally
            {
                _keepConnectCounter--;
                await tryCloseAsync();
            }
        }
        #endregion

        #region 事务操作
        private int _keepTransactionCounter = 0;
        private void beginTransaction(IsolationLevel isolationLevel)
        {
            if (Transaction == null) Transaction = Connection.BeginTransaction(isolationLevel);
        }
        private async Task beginTransactionAsync(IsolationLevel isolationLevel)
        {
            if (Transaction == null) Transaction = await Connection.BeginTransactionAsync(isolationLevel);
        }
        private void rollBackTransaction()
        {
            if (Transaction != null)
            {
                Transaction.Rollback();
                Transaction = null;
            }
        }
        private async Task rollBackTransactionAsync()
        {
            if (Transaction != null)
            {
                await Transaction.RollbackAsync();
                Transaction = null;
            }
        }
        private void commitTransaction()
        {
            if (Transaction != null)
            {
                Transaction.Commit();
                Transaction = null;
            }
        }
        private async Task commitTransactionAsync()
        {
            if (Transaction != null)
            {
                await Transaction.CommitAsync();
                Transaction = null;
            }
        }

        /// <summary>
        /// 在事务内运行,保证异常时事务回滚(try{}catch{roollback})
        /// </summary>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <param name="action">要运行的代码</param>
        public void RunInTransaction(Action action, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
        {
            if (IsTran && Transaction.IsolationLevel < isolationLevel) throw new Exception($"已经在事务中,并且当前的事务隔离级别({Transaction.IsolationLevel})小于新指定的隔离级别({isolationLevel})!");
            RunInConnection(() =>
            {
                try
                {
                    _keepTransactionCounter++;
                    beginTransaction(isolationLevel);
                    action();
                }
                catch
                {
                    rollBackTransaction();
                    throw;
                }
                finally
                {
                    _keepTransactionCounter--;
                    if (_keepTransactionCounter <= 0) commitTransaction();
                }
            });
        }

        /// <summary>
        /// 在事务内运行,保证异常时事务回滚(try{}catch{roollback})
        /// </summary>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <param name="action">要运行的代码</param>
        public async Task RunInTransactionAsync(Func<Task> action, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
        {
            if (IsTran && Transaction.IsolationLevel < isolationLevel) throw new Exception($"已经在事务中,并且当前的事务隔离级别({Transaction.IsolationLevel})小于新指定的隔离级别({isolationLevel})!");
            await RunInConnectionAsync(async () =>
            {
                try
                {
                    _keepTransactionCounter++;
                    await beginTransactionAsync(isolationLevel);
                    await action();
                }
                catch
                {
                    await rollBackTransactionAsync();
                    throw;
                }
                finally
                {
                    _keepTransactionCounter--;
                    if (_keepTransactionCounter <= 0) await commitTransactionAsync();
                }
            });
        }

        /// <summary>
        /// 在事务内运行,保证异常时事务回滚(try{}catch{roollback})
        /// </summary>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <param name="func">要运行的代码</param>
        public T RunInTransaction<T>(Func<T> func, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
        {
            if (IsTran && Transaction.IsolationLevel < isolationLevel) throw new Exception($"已经在事务中,并且当前的事务隔离级别({Transaction.IsolationLevel})小于新指定的隔离级别({isolationLevel})!");
            return RunInConnection(() =>
            {
                try
                {
                    _keepTransactionCounter++;
                    beginTransaction(isolationLevel);
                    var res = func();
                    return res;
                }
                catch
                {
                    rollBackTransaction();
                    throw;
                }
                finally
                {
                    _keepTransactionCounter--;
                    if (_keepTransactionCounter <= 0) commitTransaction();
                }
            });
        }

        /// <summary>
        /// 在事务内运行,保证异常时事务回滚(try{}catch{roollback})
        /// </summary>
        /// <param name="isolationLevel">事务隔离级别</param>
        /// <param name="func">要运行的代码</param>
        public async Task<T> RunInTransactionAsync<T>(Func<Task<T>> func, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
        {
            if (IsTran && Transaction.IsolationLevel < isolationLevel) throw new Exception($"已经在事务中,并且当前的事务隔离级别({Transaction.IsolationLevel})小于新指定的隔离级别({isolationLevel})!");
            return await RunInConnectionAsync(async () =>
            {
                try
                {
                    _keepTransactionCounter++;
                    await beginTransactionAsync(isolationLevel);
                    var res = await func();
                    return res;
                }
                catch
                {
                    await rollBackTransactionAsync();
                    throw;
                }
                finally
                {
                    _keepTransactionCounter--;
                    if (_keepTransactionCounter <= 0) await commitTransactionAsync();
                }
            });
        }
        #endregion        

        #region 测试数据库连接
        /// <summary>
        /// 测试数据库连接
        /// </summary>
        public Result OpenTest()
        {
            try
            {
                return RunInConnection(() => Result.Ok());
            }
            catch (Exception ex)
            {
                return Result.NotOk(ex?.Message);
            }
        }

        /// <summary>
        /// 测试数据库连接
        /// </summary>
        /// <returns></returns>
        public async Task<Result> OpenTestAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                return await RunInConnectionAsync(() => Task.FromResult(Result.Ok()));
            }
            catch (Exception ex)
            {
                return Result.NotOk(ex?.Message);
            }
        }
        #endregion

        #region 防止sql注入
        /// <summary>
        /// 处理用户输入字符串,防止sql注入
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public virtual string DealSqlInject(string str) => str?.Replace("'", "''");
        #endregion

        #region 将任意对象转为可拼接的sql
        /// <summary>
        /// 将任意对象转为可拼接的sql
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="args">参数,如: 
        /// <list type="number">
        /// <item>guid可使用 "N/D/B/P/X"</item>
        /// <item>datetime可使用 "yyyy-MM-dd HH:mm:ss.fff"</item>
        /// </list>
        /// </param>
        /// <returns></returns>
        public virtual Result<string> ConvertToSqlSegment(object obj)
        {
            //简单类型
            if (obj == null || obj is DBNull) return Result.Ok("null");
            if (obj is string str) return Result.Ok($"'{DealSqlInject(str)}'");
            if (obj is char c) return Result.Ok($"'{DealSqlInject(c + "")}'");
            if (obj is RawString rawStr) return Result.Ok(rawStr.String);
            if (obj is bool b) return Result.Ok(b ? "1" : "0");

            //数字
            var type = obj.GetType();
            if (types.Contains(type)) return Result.Ok(obj.ToString());

            //枚举类型
            if (type.IsEnum) return Result.Ok(obj.To<int>().ToString());

            //guid
            if (obj is Guid guid) return Result.Ok($"'{guid}'");

            //datetime
            if (obj is DateTime dateTime) return Result.Ok($"'{dateTime.ToCommonStampString()}'");

            //datetimeoffset
            if (obj is DateTimeOffset dateTimeOffset) return Result.Ok($"'{dateTimeOffset.ToString("yyyy-MM-dd HH:mm:ss.fff zzz")}'");

            //timespan
            if (obj is TimeSpan timeSpan) return Result.Ok($"'{timeSpan}'");
#if NET6_0_OR_GREATER
            if (obj is DateOnly || obj is TimeOnly) return Result.Ok($"'{obj}'");
#endif
            #region 二进制
            if (obj is IEnumerable<byte> bytes)
            {
                var sb = new StringBuilder();
                sb.Append("0x");
                foreach (var by in bytes)
                {
                    sb.Append(by.ToString("X2"));
                }
                return Result.Ok(sb.ToString());
            }
            if (obj is IEnumerable<sbyte> sbytes)
            {
                var sb = new StringBuilder();
                sb.Append("0x");
                foreach (var by in sbytes)
                {
                    sb.Append(by.ToString("X2"));
                }
                return Result.Ok(sb.ToString());
            }
            #endregion
            #region 数字集合或数组
            if (obj is IEnumerable<short> li_short) return Result.Ok($"({li_short.ToStringSeparated(",")})");
            if (obj is IEnumerable<ushort> li_ushort) return Result.Ok($"({li_ushort.ToStringSeparated(",")})");
            if (obj is IEnumerable<int> li_int) return Result.Ok($"({li_int.ToStringSeparated(",")})");
            if (obj is IEnumerable<uint> li_uint) return Result.Ok($"({li_uint.ToStringSeparated(",")})");
            if (obj is IEnumerable<long> li_long) return Result.Ok($"({li_long.ToStringSeparated(",")})");
            if (obj is IEnumerable<ulong> li_ulong) return Result.Ok($"({li_ulong.ToStringSeparated(",")})");
            if (obj is IEnumerable<float> li_float) return Result.Ok($"({li_float.ToStringSeparated(",")})");
            if (obj is IEnumerable<double> li_double) return Result.Ok($"({li_double.ToStringSeparated(",")})");
            if (obj is IEnumerable<decimal> li_decimal) return Result.Ok($"({li_decimal.ToStringSeparated(",")})");
            #endregion

            return Result.NotOk($"未能转换 {obj.GetType().FullName} 类型数据到sql!");
        }
        private static List<Type> types = new List<Type>()
        {
            typeof(sbyte), typeof(byte),
            typeof(short), typeof(ushort),
            typeof(int), typeof(uint),
            typeof(long), typeof(ulong),
            typeof(float), typeof(double), typeof(decimal)
        };
        #endregion

        #region CreatePara 创建参数
        /// <summary>
        /// 创建参数
        /// </summary>
        public abstract DbParameter CreatePara();

        /// <summary>
        /// 创建参数
        /// </summary>
        /// <param name="name">参数名称</param>
        /// <param name="value">参数值</param>
        /// <param name="direction"></param>
        /// <param name="dbType"></param>
        /// <param name="size"></param>
        /// <param name="precision"></param>
        /// <param name="scale"></param>
        public virtual DbParameter CreatePara(string name, object value,
            ParameterDirection? direction = null,
            DbType? dbType = null, int? size = null,
            byte? precision = null, byte? scale = null)
        {
            var para = CreatePara();
            para.ParameterName = name;
            para.Value = value;
            if (direction != null) para.Direction = direction.Value;
            if (dbType != null) para.DbType = dbType.Value;
            if (size != null) para.Size = size.Value;
            if (precision != null) para.Precision = precision.Value;
            if (scale != null) para.Scale = scale.Value;
            return para;
        }
        #endregion

        #region 获取此实例内的参数标记前缀
        private int paraPrefix = 0;
        protected virtual string GetCounter()
        {
            var t = Interlocked.Increment(ref paraPrefix);
            if (t < 0)
            {

                return t.ToString().Replace("-", "_");
            }
            return t.ToString();
        }
        #endregion        

        #region 生成分页查询语句: GetSqlForPageSize
        /// <summary>
        /// 生成分页查询语句
        /// </summary>
        /// <param name="selectSql">select子句,如:select id,name from person where age>10</param>
        /// <param name="strOrder">排序子句,必须指定,如:order by id</param>
        /// <param name="PageSize">分页大小,如:10</param>
        /// <param name="PageIndex">当前页码,如:1</param>
        /// <returns>返回示例(mysql):select id,name from person where age>10 order by id limit 0,10</returns>
        public abstract string GetSqlForPageSize(string selectSql, string strOrder, int PageSize, int PageIndex);
        #endregion

        #region Is系列: 判断表/视图/列/存储过程/触发器是否存在       

        /// <summary>
        /// 判断指定表或视图中是否有某一列
        /// </summary>
        /// <param name="tableOrViewName">表或视图名</param>
        /// <param name="columnName">列名</param>
        /// <param name="schemaName">模式名</param>
        /// <returns>返回列是否存在</returns>
        public virtual bool IsColumnExistInTableOrView(string tableOrViewName, string columnName, string schemaName = null)
        {
            tableOrViewName = DealSqlInject(tableOrViewName);
            columnName = DealSqlInject(columnName);
            schemaName = DealSqlInject(schemaName);
            var objName = ParseObjectName(tableOrViewName, schemaName);
            columnName = ParseObjectName(columnName).Name;
            string sql = $@"select count(1)
from INFORMATION_SCHEMA.COLUMNS
where
    TABLE_NAME='{objName.Name}'
    and
    COLUMN_NAME='{columnName}'";
            if (objName.SchemaName.IsNotNullOrEmptyOrWhiteSpace())
            {
                sql += $"\r\n and t.TABLE_SCHEMA='{objName.SchemaName}'";
            }
            int r = int.Parse(SelectScalar<string>(sql));
            return r > 0;
        }

        /// <summary>
        /// 判断指定表中是否有某一列
        /// </summary>
        /// <param name="tableName">表名，如: [dbo].[table1]、table1、`table1`、`testdb`.`table1`</param>
        /// <param name="columnName">列名</param>
        /// <param name="schemaName">模式名</param>
        /// <returns>返回列是否存在</returns>
        public virtual bool IsColumnExistInTable(string tableName, string columnName, string schemaName = null)
        {
            tableName = DealSqlInject(tableName);
            columnName = DealSqlInject(columnName);
            schemaName = DealSqlInject(schemaName);
            var objName = ParseObjectName(tableName, schemaName);
            columnName = ParseObjectName(columnName).Name;

            string sql = $@"select count(1)
from INFORMATION_SCHEMA.COLUMNS c
    left join INFORMATION_SCHEMA.tables t
    on c.TABLE_CATALOG=t.TABLE_CATALOG and c.TABLE_SCHEMA=t.TABLE_SCHEMA and c.TABLE_NAME=t.TABLE_NAME
where
    c.COLUMN_NAME='{columnName}'
    and
    c.TABLE_NAME='{objName.Name}'
    and t.TABLE_TYPE='BASE TABLE'";
            if (objName.SchemaName.IsNotNullOrEmptyOrWhiteSpace())
            {
                sql += $"\r\n and t.TABLE_SCHEMA='{objName.SchemaName}'";
            }
            int r = int.Parse(SelectScalar<string>(sql));
            return r > 0;
        }

        /// <summary>
        /// 判断指定视图中是否有某一列
        /// </summary>
        /// <param name="viewName">视图名，如: [dbo].[table1]、table1、`table1`、`testdb`.`table1`</param>
        /// <param name="columnName">列名</param>
        /// <param name="schemaName">模式名</param>
        /// <returns>返回列是否存在</returns>
        public virtual bool IsColumnExistInView(string viewName, string columnName, string schemaName = null)
        {
            viewName = DealSqlInject(viewName);
            columnName = DealSqlInject(columnName);
            schemaName = DealSqlInject(schemaName);
            var objName = ParseObjectName(viewName, schemaName);
            columnName = ParseObjectName(columnName).Name;

            var tuple = AnalysisIdentifier(viewName);
            string sql = $@"select count(1)
from INFORMATION_SCHEMA.COLUMNS c
    left join INFORMATION_SCHEMA.tables t
    on c.TABLE_CATALOG=t.TABLE_CATALOG and c.TABLE_SCHEMA=t.TABLE_SCHEMA and c.TABLE_NAME=t.TABLE_NAME
where
    c.COLUMN_NAME='{columnName}'
    and
    c.TABLE_NAME='{objName.Name}'
    and t.TABLE_TYPE='VIEW'";
            if (objName.SchemaName.IsNotNullOrEmptyOrWhiteSpace())
            {
                sql += $"\r\n and t.TABLE_SCHEMA='{objName.SchemaName}'";
            }
            int r = int.Parse(SelectScalar<string>(sql));
            return r > 0;
        }

        /// <summary>
        /// 判断表或视图是否存在
        /// </summary>
        /// <param name="tableOrViewName">表或视图名，如: [dbo].[table1]、table1、`table1`、`testdb`.`table1`</param>
        /// <param name="schemaName">模式名</param>
        /// <returns>返回表或视图是否存在</returns>
        public virtual bool IsTableOrViewExist(string tableOrViewName, string schemaName = null)
        {
            tableOrViewName = DealSqlInject(tableOrViewName);
            schemaName = DealSqlInject(schemaName);
            var objName = ParseObjectName(tableOrViewName, schemaName);

            string sql = $"select count(1) from INFORMATION_SCHEMA.TABLES where TABLE_NAME='{objName.Name}'";
            if (objName.SchemaName.IsNotNullOrEmptyOrWhiteSpace()) sql += $" and TABLE_SCHEMA='{objName.SchemaName}'";
            int r = SelectScalar<int>(sql);
            return r > 0;
        }

        /// <summary>
        /// 判断表是否存在
        /// </summary>
        /// <param name="tableName">表名，如: [dbo].[table1]、table1、`table1`、`testdb`.`table1`</param>
        /// <param name="schemaName">模式名</param>
        /// <returns>返回表是否存在</returns>
        public virtual bool IsTableExist(string tableName, string schemaName = null)
        {
            tableName = DealSqlInject(tableName);
            schemaName = DealSqlInject(schemaName);
            var objName = ParseObjectName(tableName, schemaName);

            string sql = $"select count(1) from INFORMATION_SCHEMA.TABLES where TABLE_NAME='{objName.Name}' and TABLE_TYPE='BASE TABLE'";
            if (objName.SchemaName.IsNotNullOrEmptyOrWhiteSpace()) sql += $" and TABLE_SCHEMA='{DealSqlInject(objName.SchemaName)}'";
            int r = SelectScalar<int>(sql);
            return r > 0;
        }

        /// <summary>
        /// 判断视图是否存在
        /// </summary>
        /// <param name="viewName">视图名，如: [dbo].[table1]、table1、`table1`、`testdb`.`table1`</param>
        /// <param name="schemaName">模式名</param>
        /// <returns>返回视图是否存在</returns>
        public virtual bool IsViewExist(string viewName, string schemaName = null)
        {
            viewName = DealSqlInject(viewName);
            schemaName = DealSqlInject(schemaName);
            var objName = ParseObjectName(viewName, schemaName);

            string sql = $"select count(1) from INFORMATION_SCHEMA.TABLES where TABLE_NAME='{objName.Name}' and TABLE_TYPE='VIEW'";
            if (objName.SchemaName.IsNotNullOrEmptyOrWhiteSpace()) sql += $" and TABLE_SCHEMA='{objName.SchemaName}'";
            int r = SelectScalar<int>(sql);
            return r > 0;
        }

        /// <summary>
        /// 判断存储过程是否存在
        /// </summary>
        /// <param name="procName">存储过程名称</param>
        /// <param name="schemaName">模式名</param>
        /// <returns></returns>
        public abstract bool IsProcedureExist(string procName, string schemaName = null);

        /// <summary>
        /// 判断触发器是否存在
        /// </summary>
        /// <param name="triggerName">触发器名称</param>
        /// <param name="schemaName">模式名</param>
        /// <returns></returns>
        public abstract bool IsTriggerExist(string triggerName, string schemaName = null);
        #endregion

        #region CreateNewDB
        /// <summary>
        /// 根据当前的数据库类型和连接字符串创建一个新的数据库操作对象
        /// </summary>
        /// <returns></returns>
        public DBAccess CreateNewDB()
        {
            return DBFactory.CreateDB(DBType, DBConn, Settings.Clone());
        }
        #endregion

        #region Id和流水号生成控制器
        /// <summary>
        /// 初始化基础数据库缓存的Id和流水号生成环境
        /// </summary>
        /// <returns></returns>
        protected abstract bool InitDBCacheGenerator();

        private static ConcurrentDictionary<string, bool> _initGenerators = new ConcurrentDictionary<string, bool>();
        /// <summary>
        /// 确保已经调用过<seealso cref="InitDBCacheGenerator"/>方法
        /// </summary>
        protected void EnsureInitGenerator()
        {
            if (!_initGenerators.TryGetValue(DBConn, out bool flag))
            {
                lock (typeof(DBAccess))
                {
                    if (!_initGenerators.TryGetValue(DBConn, out bool flag2))
                    {
                        var b = InitDBCacheGenerator();
                        if (b)
                        {
                            _initGenerators.TryAdd(DBConn, true);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 根据指定的表名和列名生成Id(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">指定的表名</param>
        /// <param name="colName">指定的列名</param>
        /// <returns></returns>
        protected abstract long InternalNewId(string tableName, string colName);
        /// <summary>
        /// 根据指定的表名和列名生成Id(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">指定的表名</param>
        /// <param name="colName">指定的列名</param>
        /// <returns></returns>
        /// <remarks>注意：为了避免受事务的影响，该方法将调用<seealso cref="CreateNewDB(Action{DBSetting})"/>生成新的数据库连接，然后再执行Id生成</remarks>
        public virtual long NewId(string tableName, string colName) => (IsTran ? CreateNewDB() : this).InternalNewId(tableName, colName);

        /// <summary>
        /// 根据指定的表名和列名批量生成Id(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">指定的表名</param>
        /// <param name="colName">指定的列名</param>
        /// <param name="count">生成的Id的数量</param>
        /// <returns></returns>
        protected abstract List<long> InternalNewIds(string tableName, string colName, int count);
        /// <summary>
        /// 根据指定的表名和列名批量生成Id(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">指定的表名</param>
        /// <param name="colName">指定的列名</param>
        /// <param name="count">生成的Id的数量</param>
        /// <returns></returns>
        /// <remarks>注意：为了避免受事务的影响，该方法将调用<seealso cref="CreateNewDB(Action{DBSetting})"/>生成新的数据库连接，然后再执行Id生成</remarks>
        public virtual List<long> NewIds(string tableName, string colName, int count) => (IsTran ? CreateNewDB() : this).InternalNewIds(tableName, colName, count);

        /// <summary>
        /// 重置一个表的Id生成控制,这将删除数据库缓存的生成记录(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <returns></returns>
        protected virtual void InternalResetId(string tableName, string colName)
        {
            EnsureInitGenerator();
            Ensure.NotNullOrEmptyOrWhiteSpace(tableName);
            Ensure.NotNullOrEmptyOrWhiteSpace(colName);
            tableName = DealSqlInject(tableName);
            colName = DealSqlInject(colName);
            Delete(Settings.DBCacheGeneratorIdTableName, $" and tablename={ParaPrefix}tablename and colname={ParaPrefix}colname", new { tablename = tableName, colname = colName }.ToDictionary());
        }

        /// <summary>
        /// 重置一个表的Id生成控制,这将删除数据库缓存的生成记录(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <returns></returns>
        /// <remarks>注意：为了避免受事务的影响，该方法将调用<seealso cref="CreateNewDB(Action{DBSetting})"/>生成新的数据库连接，然后再执行Id重置</remarks>
        public virtual void ResetId(string tableName, string colName) => (IsTran ? CreateNewDB() : this).InternalResetId(tableName, colName);

        protected virtual long InternalGetCurrentId(string tableName, string colName)
        {
            EnsureInitGenerator();
            Ensure.NotNullOrEmptyOrWhiteSpace(tableName);
            Ensure.NotNullOrEmptyOrWhiteSpace(colName);
            tableName = DealSqlInject(tableName);
            colName = DealSqlInject(colName);
            var sql = $"select currentid from {Settings.DBCacheGeneratorIdTableName} where tablename='{tableName}' and colname='{colName}'";
            var current = SelectScalar<long?>(sql);
            return current ?? 0;
        }

        /// <summary>
        /// 获取当前Id值,尚未生成返回0
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        public virtual long GetCurrentId(string tableName, string colName) => (IsTran ? CreateNewDB() : this).InternalGetCurrentId(tableName, colName);

        /// <summary>
        /// 解析格式准备流水号生成
        /// </summary>
        /// <param name="format"></param>
        /// <param name="now"></param>
        /// <param name="machineIdString"></param>
        /// <returns></returns>
        protected (string likestr, DateTime snoNow, int startindex, string statictext, string machineIdString) PrePareForSNO(SerialFormat format, DateTime now, string machineIdString)
        {
            if (machineIdString.IsNullOrEmptyOrWhiteSpace()) machineIdString = DotNetCommon.Machine.MachineIdString;
            var (likestr, snoNow, startindex) = SerialFormat.Parse(format, now, machineIdString);
            var statictext = "";
            var chunks = format.Chunks;
            for (int i = 0, len = chunks.Count; i < len; i++)
            {
                var _chunk = chunks[i];
                if (_chunk.Type == SerialFormatChunkType.StaticText)
                {
                    statictext += _chunk.FormatString;
                }
                else if (_chunk.Type == SerialFormatChunkType.MachineText)
                {
                    statictext += machineIdString.PadLeft(4, '0');
                }
            }
            return (likestr, snoNow, startindex, statictext, machineIdString);
        }

        /// <summary>
        /// 根据表名和列名生成流水号(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <param name="format">流水号格式</param>
        /// <returns></returns>
        protected abstract string InternalNewSNO(string tableName, string colName, SerialFormat format);
        /// <summary>
        /// 根据表名和列名生成流水号(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <param name="format">流水号格式</param>
        /// <returns></returns>
        /// <remarks>注意：为了避免受事务的影响，该方法将调用<seealso cref="CreateNewDB(Action{DBSetting})"/>生成新的数据库连接，然后再执行流水号生成</remarks>
        public virtual string NewSNO(string tableName, string colName, SerialFormat format) => (IsTran ? CreateNewDB() : this).InternalNewSNO(tableName, colName, format);

        /// <summary>
        /// 根据表名和列名批量生成流水号(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <param name="format">流水号格式</param>
        /// <param name="count">生成的流水号的数量</param>
        /// <returns></returns>
        protected abstract List<string> InternalNewSNOs(string tableName, string colName, SerialFormat format, int count);
        /// <summary>
        /// 根据表名和列名批量生成流水号(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <param name="format">流水号格式</param>
        /// <param name="count">生成的流水号的数量</param>
        /// <returns></returns>
        /// <remarks>注意：为了避免受事务的影响，该方法将调用<seealso cref="CreateNewDB(Action{DBSetting})"/>生成新的数据库连接，然后再执行流水号生成</remarks>
        public virtual List<string> NewSNOs(string tableName, string colName, SerialFormat format, int count) => (IsTran ? CreateNewDB() : this).InternalNewSNOs(tableName, colName, format, count);

        /// <summary>
        /// 重置流水号(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <param name="serialFormat">格式</param>
        protected virtual void InternalResetSNO(string tableName, string colName, SerialFormat serialFormat = null)
        {
            EnsureInitGenerator();
            Ensure.NotNullOrEmptyOrWhiteSpace(tableName);
            Ensure.NotNullOrEmptyOrWhiteSpace(colName);
            tableName = DealSqlInject(tableName);
            colName = DealSqlInject(colName);
            if (serialFormat != null)
            {
                var text = PrePareForSNO(serialFormat, DateTime.Now, DotNetCommon.Machine.MachineIdString).statictext;
                Delete(Settings.DBCacheGeneratorSNOTableName, $" and tablename={ParaPrefix}tablename and colname={ParaPrefix}colname and statictext={ParaPrefix}statictext", new { tablename = tableName, colname = colName }.ToDictionary());
            }
            else
            {
                Delete(Settings.DBCacheGeneratorSNOTableName, $" and tablename={ParaPrefix}tablename and colname={ParaPrefix}colname", new { tablename = tableName, colname = colName }.ToDictionary());
            }
        }
        /// <summary>
        /// 重置流水号(基于数据库缓存)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="colName">列名</param>
        /// <param name="serialFormat">格式</param>
        /// <remarks>注意：为了避免受事务的影响，该方法将调用<seealso cref="CreateNewDB(Action{DBSetting})"/>生成新的数据库连接，然后再执行流水号重置</remarks>
        public virtual void ResetSNO(string tableName, string colName, SerialFormat serialFormat = null) => (IsTran ? CreateNewDB() : this).InternalResetSNO(tableName, colName);
        #endregion

        #region 基于数据库的分布式锁 RunInLock
        private static ConcurrentDictionary<string, bool> _lockcaches = new ConcurrentDictionary<string, bool>();
        private static ConcurrentDictionary<string, SemaphoreSlim> _lockSemaphores = new ConcurrentDictionary<string, SemaphoreSlim>();

        private void EnsureInitLock()
        {
            if (!_lockcaches.ContainsKey(DBConn))
            {
                lock (typeof(DBAccess))
                {
                    if (!_lockcaches.ContainsKey(DBConn))
                    {
                        if (!IsTableExist(Settings.DBLockTableName))
                        {
                            #region 新建表 Settings.DBLockTableName
                            ExecuteSql($@"
create table {Settings.DBLockTableName}(
	lock_str varchar(200) unique not null,
	lock_time {DateTimeSqlSegment.DefaultDateTimeType} default({DateTimeSqlSegment.Current}),
    lock_createtime {DateTimeSqlSegment.DefaultDateTimeType} default({DateTimeSqlSegment.Current}),
	lock_user varchar(200) not null
)");
                            #endregion
                        }
                        _lockcaches.TryAdd(DBConn, true);
                    }
                }
            }
        }

        private async Task<Result> TryGetLock(DateTime starttime, string lock_str, string lock_user, int timeoutSecond = 60 * 5)
        {
            EnsureInitLock();
            while (true)
            {
                try
                {
                    await ExecuteSqlAsync($"insert into {Settings.DBLockTableName}(lock_str,lock_user) values('{lock_str}','{lock_user}')");
                    StartLockMonitor(lock_str, lock_user);
                    return Result.Ok();
                }
                catch (Exception ex)
                {
                    var endtime = DateTime.Now;
                    var span = endtime - starttime;
                    if (span.TotalSeconds > timeoutSecond)
                    {
                        return Result.NotOk($"获取锁[{lock_str}]超时:{ex?.Message}]");
                    }
                    await Task.Delay(500);
                    //删除20秒之前的,20秒内已获取锁的程序肯定会更新时间
                    try
                    {
                        await ExecuteSqlAsync($"delete from {Settings.DBLockTableName} where lock_time <{DateTimeSqlSegment.GetCurrentAddSecond(-20)}");
                    }
                    catch (Exception ex2)
                    {
                        return Result.NotOk($"获取锁[{lock_str}]失败:{ex2?.Message}]");
                    }
                }
            }
        }

        private void StartLockMonitor(string lock_str, string lock_user)
        {
            Task.Run(async () =>
            {
                while (true)
                {
                    //分布式时 休息5秒
                    await Task.Delay(5 * 1000);
                    //将当前的锁刷新时长
                    try
                    {
                        int count = await ExecuteSqlAsync($"update {Settings.DBLockTableName} set lock_time= {DateTimeSqlSegment.Current} where lock_str='{lock_str}' and lock_user='{lock_user}'");
                        if (count != 1) break;
                    }
                    catch (Exception ex)
                    {
                        logger.LogError($"刷新锁时间失败(lock_str={lock_str},lock_user={lock_user}):{ex?.Message}");
                        break;
                    }
                }
            });
        }

        private void TryReleaseLock(string lock_str, string lock_user)
        {
            EnsureInitLock();
            ExecuteSql($"delete from {Settings.DBLockTableName} where lock_str='{lock_str}' and lock_user='{lock_user}'");
        }

        /// <summary>
        /// 在数据库的分布式锁内运行，示例：<br/><br/>
        /// <code>
        /// RunInLock("keystring", () => { /*do something*/});
        /// </code>
        /// </summary>
        /// <remarks>
        /// 对于mysql和sqlserver来说，都是在将当前链接变为长链接，并加上会话锁<br/>
        /// <list type="number">
        /// <item>sqlserver: sp_getAppLock</item>
        /// <item>mysql: GET_LOCK</item>
        /// </list>
        /// </remarks>
        public void RunInLock(string lock_str, Action action, int getLockTimeoutSecond = 60 * 3)
        {
            Ensure.NotNull(lock_str, nameof(lock_str));
            Ensure.NotNull(action, nameof(action));
            var task = RunInLockInternalAsync(lock_str, async () =>
            {
                action();
                return Task.CompletedTask;
            }, getLockTimeoutSecond);
            task.Wait();
        }

        /// <summary>
        /// 在数据库的分布式锁内运行，示例：<br/><br/>
        /// <code>
        /// RunInLock("keystring", () => { /*do something*/ return new { id = 1, name = "小明" }; });
        /// </code>
        /// </summary>
        /// <remarks>
        /// 对于mysql和sqlserver来说，都是在将当前链接变为长链接，并加上会话锁<br/>
        /// <list type="number">
        /// <item>sqlserver: sp_getAppLock</item>
        /// <item>mysql: GET_LOCK</item>
        /// </list>
        /// </remarks>
        public T RunInLock<T>(string lock_str, Func<T> func, int getLockTimeoutSecond = 60 * 3)
        {
            Ensure.NotNull(lock_str, nameof(lock_str));
            Ensure.NotNull(func, nameof(func));
            var task = RunInLockInternalAsync(lock_str, () =>
            {
                var res = func();
                return Task.FromResult(res);
            }, getLockTimeoutSecond);
            return task.Result;
        }

        /// <summary>
        /// 在数据库的分布式锁内运行，示例：<br/><br/>
        /// <code>
        /// await RunInLockAsync("keystring", async () => { /*do something*/});
        /// </code>
        /// </summary>
        /// <remarks>
        /// 对于mysql和sqlserver来说，都是在将当前链接变为长链接，并加上会话锁<br/>
        /// <list type="number">
        /// <item>sqlserver: sp_getAppLock</item>
        /// <item>mysql: GET_LOCK</item>
        /// </list>
        /// </remarks>
        public async Task RunInLockAsync(string lock_str, Func<Task> func, int getLockTimeoutSecond = 60 * 3)
        {
            Ensure.NotNull(lock_str, nameof(lock_str));
            Ensure.NotNull(func, nameof(func));
            await RunInLockInternalAsync(lock_str, async () =>
            {
                await func();
                return Task.CompletedTask;
            }, getLockTimeoutSecond);
        }

        /// <summary>
        /// 在数据库的分布式锁内运行，示例：<br/><br/>
        /// <code>
        /// await RunInLockAsync("keystring", async () => { /*do something*/ return new { id = 1, name = "小明" }; });
        /// </code>
        /// </summary>
        /// <remarks>
        /// 对于mysql和sqlserver来说，都是在将当前链接变为长链接，并加上会话锁<br/>
        /// <list type="number">
        /// <item>sqlserver: sp_getAppLock</item>
        /// <item>mysql: GET_LOCK</item>
        /// </list>
        /// </remarks>
        public async Task<T> RunInLockAsync<T>(string lock_str, Func<Task<T>> func, int getLockTimeoutSecond = 60 * 3)
        {
            Ensure.NotNull(lock_str, nameof(lock_str));
            Ensure.NotNull(func, nameof(func));
            return await RunInLockInternalAsync(lock_str, func, getLockTimeoutSecond);
        }

        protected virtual async Task<T> RunInLockInternalAsync<T>(string lock_str, Func<Task<T>> func, int getLockTimeoutSecond)
        {
            //先单机拦截并发
            var now = DateTime.Now;
            var asyncLock = _lockSemaphores.GetOrAdd(lock_str, _ => new SemaphoreSlim(1, 1));
            var b = await asyncLock.WaitAsync(getLockTimeoutSecond * 1000);
            if (!b) throw new Exception($"获取锁[{lock_str}]超时,单机内超时.");
            try
            {
                //单机通过后,再数据库锁内拦截
                var lock_user = $"{now.ToCommonStampString()} {Guid.NewGuid().ToString().Replace("-", "").ToLower()}";
                var res = await TryGetLock(now, lock_str, lock_user, getLockTimeoutSecond);
                if (res.Success)
                {
                    try
                    {
                        var result = await func();
                        return result;
                    }
                    finally
                    {
                        TryReleaseLock(lock_str, lock_user);
                    }
                }
                else
                {
                    throw new Exception(res.Message);
                }
            }
            finally
            {
                try { asyncLock.Release(); } catch { }
            }
        }
        #endregion

        #region 数据库管理对象 Manage
        /// <summary>
        /// 数据库管理对象
        /// </summary>
        public abstract DBManage Manage { get; }
        #endregion        

        #region 运算符
        private DateTimeSqlSegment dateTimeSqlSegment = null;
        protected abstract DateTimeSqlSegment GetDateTimeSqlSegment();
        public virtual DateTimeSqlSegment DateTimeSqlSegment
        {
            get
            {
                if (dateTimeSqlSegment != null) return dateTimeSqlSegment;
                dateTimeSqlSegment = GetDateTimeSqlSegment();
                return dateTimeSqlSegment;
            }
        }

        private StringSqlSegment stringSqlSegment = null;
        protected abstract StringSqlSegment GetStringSqlSegment();
        /// <summary>
        /// 数据库字符串运算符，示例：
        /// <list type="number">
        /// <item>sqlserver: GetLength("name",true) => "len(ISNULL(null,''))"</item>
        /// <item>sqlserver: AfterString("name","-") => "SUBSTRING(name,(charindex('-',name)+len('-')),LEN(name))"</item>
        /// </list>
        /// </summary>
        public virtual StringSqlSegment StringSqlSegment
        {
            get
            {
                if (stringSqlSegment != null) return stringSqlSegment;
                stringSqlSegment = GetStringSqlSegment();
                return stringSqlSegment;
            }
        }
        #endregion

        #region 获取刚插入的自增id的Sql语句
        /// <summary>
        /// 获取刚插入的自增id的Sql语句
        /// </summary>
        /// <remarks>
        /// <list type="number">
        /// <item>sqlserver: select SCOPE_IDENTITY()</item>
        /// <item>mysql: SELECT LAST_INSERT_ID()</item>
        /// <item>oracle: 只能用序列实现</item>
        /// <item>postgresql: 可以使用serial定义列类型，但实际上也是序列</item>
        /// <item>sqlite: select last_insert_rowid()</item>
        /// </list>
        /// </remarks>
        /// <param name="sequenceName">序列名称</param>
        /// <returns></returns>
        public abstract string GetInsertedId(string sequenceName = null);
        #endregion

        #region reader转model的编译表达式
        private static ConcurrentDictionary<(string readerCode, Type type), object> cacheDictionary = new ConcurrentDictionary<(string readerCode, Type type), object>();
        public Func<IDataReader, T> GetFunc<T>(IDataReader reader)
        {
            var counter = reader.FieldCount;
            var names = new List<string>(counter);
            for (var i = 0; i < counter; i++)
            {
                names.Add(reader.GetName(i));
            }
            var names2 = names.ToList();
            var readerCode = names.ToStringSeparated("#");
            var type = typeof(T);
            var func = cacheDictionary.GetOrAdd((readerCode, type), key =>
              {
                  var props = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(i => i.CanWrite).ToList();

                  var colAttrNames = new Dictionary<string, string>();
                  foreach (var prop in props)
                  {
                      var attr = prop.GetCustomAttributes(true).FirstOrDefault(i => i is ColumnAttribute) as ColumnAttribute;
                      if (attr != null)
                      {
                          colAttrNames.Add(prop.Name, attr.Name);
                      }
                  }

                  var map = new Dictionary<string, PropertyInfo>();
                  //第一遍: 全匹配
                  for (int i = 0; i < props.Count; i++)
                  {
                      var prop = props[i];
                      colAttrNames.TryGetValue(prop.Name, out var attrColName);
                      var index = names.FindIndex(i => i == prop.Name || (attrColName.IsNotNullOrEmptyOrWhiteSpace() && i == attrColName));
                      if (index >= 0)
                      {
                          map.Add(names[index], prop);
                          props.RemoveAt(i);
                          names.RemoveAt(index);
                          i--;
                          continue;
                      }
                  }
                  //第二遍: 忽略大小写
                  if (props.Count > 0 && names.Count > 0)
                  {
                      for (int i = 0; i < props.Count; i++)
                      {
                          var prop = props[i];
                          var index = names.FindIndex(i => i.ToLower() == prop.Name.ToLower());
                          if (index >= 0)
                          {
                              map.Add(names[index], prop);
                              props.RemoveAt(i);
                              names.RemoveAt(index);
                              i--;
                              continue;
                          }
                      }
                  }
                  //第三遍: 忽略大小写,忽略下划线
                  if (props.Count > 0 && names.Count > 0)
                  {
                      for (int i = 0; i < props.Count; i++)
                      {
                          var prop = props[i];
                          var index = names.FindIndex(i => i.Replace("_", "").ToLower() == prop.Name.Replace("_", "").ToLower());
                          if (index >= 0)
                          {
                              map.Add(names[index], prop);
                              props.RemoveAt(i);
                              names.RemoveAt(index);
                              i--;
                              continue;
                          }
                      }
                  }

                  //生成表达式
                  var para = Expression.Parameter(typeof(IDataReader), "reader");
                  //var res=new T();
                  var variable = Expression.Variable(type, "res");
                  var newExp = Expression.New(type.GetConstructor(new Type[0]));
                  var assign = Expression.Assign(variable, newExp);
                  //属性赋值
                  var assignProps = new List<BinaryExpression>();
                  if (map.Count > 0)
                  {
                      var readerType = typeof(IDataRecord);
                      var getValue = readerType.GetMethod("GetValue", new Type[] { typeof(int) });
                      var toMethod = typeof(DotNetCommon.Extensions.ObjectExtensions).GetMethod("To", new Type[] { typeof(object), typeof(Type), typeof(object[]) });

                      foreach (var item in map)
                      {
                          var prop = item.Value;
                          var proptype = prop.PropertyType;
                          var name = item.Key;
                          var index = names2.IndexOf(name);
                          //res.Prop=reader.GetValue(index).To(typeof(int));
                          var dataExp = Expression.Call(para, getValue, Expression.Constant(index));
                          var resultExp = Expression.Call(null, toMethod, dataExp, Expression.Constant(proptype), Expression.Constant(new Type[0]));
                          var convertExp = Expression.Convert(resultExp, proptype, null);
                          var assignProp = Expression.Assign(Expression.Property(variable, prop.Name), convertExp);
                          assignProps.Add(assignProp);
                      }
                  }

                  //return res;
                  var labelTarget = Expression.Label(type);
                  var labelExpression = Expression.Label(labelTarget, variable);
                  var gotoExpression = Expression.Return(labelTarget, variable, type);

                  var expressions = new List<Expression>();
                  expressions.Add(assign);
                  expressions.AddRange(assignProps);
                  expressions.Add(gotoExpression);
                  expressions.Add(labelExpression);

                  //组装表达式块,编译生成委托
                  var block = Expression.Block(type, new ParameterExpression[] { variable }, expressions);
                  var mapperFunc = Expression.Lambda<Func<IDataReader, T>>(block, para).Compile();
                  return mapperFunc;
              });
            return func as Func<IDataReader, T>;
        }
        #endregion

        /// <summary>
        /// 将传入的 filter 转成 where语句，示例:
        /// <list type="bullet">
        /// <item>传入: "and id>10" 返回: "where 1=1 and id>10"</item>
        /// <item>传入: "id>10" 返回: "where id>10"</item>
        /// <item>传入: "" 返回: "where 1=1"</item>
        /// </list>
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public string LinkWhereFilter(string filter)
        {
            if (filter.IsNullOrEmptyOrWhiteSpace()) return "where 1=1";
            var tmp = filter.Trim().ToUpper();
            if (tmp.StartsWith("AND ") || tmp.StartsWith("OR "))
            {
                return $"where 1=1 {filter}";
            }
            else
            {
                return $"where {filter}";
            }
        }

        #region 序列
        /// <summary>
        /// 是否支持序列
        /// </summary>
        /// <returns></returns>
        public abstract bool IsSupportSequence();

        /// <summary>
        /// 获取 下一个序列值 的sql语句
        /// </summary>
        /// <param name="name">序列名称</param>
        /// <returns></returns>
        public abstract string NextSequenceValue(string name);
        #endregion
    }
}